//sysfs 是 Linux 内核自动创建的一个虚拟文件系统（挂载在 /sys），用于展示系统中所有设备、驱动、总线、模块的状态和配置
/*
/sys/class/	自定义逻辑设备，面向用户
/sys/bus/	总线相关信息
/sys/devices/	实际硬件设备树
/sys/kernel/debug/	用于调试信息(需挂载 debugfs)
*/
#define pr_fmt(fmt)			"KBUILD_MODNAME:%s-%d:" fmt,__func__,__LINE__

#include <linux/sysfs.h>
#include <linux/module.h>
#include <linux/device.h>

static int my_value = 0;

static ssize_t mydev_show(struct device *dev,
                          struct device_attribute *attr, char *buf)
{
    return sprintf(buf, "%d\n", my_value);
}

static ssize_t mydev_store(struct device *dev,
                           struct device_attribute *attr,
                           const char *buf, size_t count)
{
    sscanf(buf, "%d", &my_value);
    return count;
}

static DEVICE_ATTR(enable, 0664, mydev_show, mydev_store);

// static DEVICE_ATTR(status, 0444, mydev_status_show, NULL);
// static DEVICE_ATTR(mode, 0664, mydev_mode_show, mydev_mode_store);

// static struct attribute *mydev_attrs[] = {
//     &dev_attr_enable.attr,
//     &dev_attr_status.attr,
//     &dev_attr_mode.attr,
//     NULL,
// };

// static const struct attribute_group mydev_attr_group = {
//     .attrs = mydev_attrs,
// };

// sysfs_create_group(&mydev_device->kobj, &mydev_attr_group);

static struct class *mydev_class;
static struct device *mydev_device;
static dev_t dev_major;
#define DEV_MAX 1

static int __init sysfs_test_init(void)
{
	int retval = -ENXIO;

    // sys/class/mydev
    mydev_class = class_create( "mydev");
    if (IS_ERR(mydev_class)) {
		pr_err("class_create failed\n");
		return -EFAULT;
	}

    pr_info("class_create ok\n");

    //dev_major 输出参数,0:次设备号起始号,DEV_MAX:要分配的次设备号数,mydev:设备名.成功返回0
	retval = alloc_chrdev_region(&dev_major, 0, DEV_MAX, "mydev");
    if (retval)
		goto err_chardev_region;

    pr_info("major = %d, minor = %d\n", MAJOR(dev_major), MINOR(dev_major));

    // sys/class/mydev/mydev0 ,/dev/mydev0
    mydev_device = device_create(mydev_class, NULL, dev_major, NULL, "mydev0");
    if (IS_ERR(mydev_device)) {
		pr_err("failed to create device\n");
		goto err_dev;
	}

    pr_info("device_create ok\n");

    //echo 1 > /sys/class/mydev/mydev0/enable
    retval = device_create_file(mydev_device, &dev_attr_enable);
    if (retval)
		goto error_dev_file;
    pr_info("\n");
    return 0;

error_dev_file:
    device_destroy(mydev_class, dev_major);
err_dev:
	unregister_chrdev_region(dev_major, DEV_MAX);
err_chardev_region:
	class_destroy(mydev_class);
	return -EFAULT;

}

static void __exit sysfs_test_exit(void)
{
    device_remove_file(mydev_device, &dev_attr_enable);
    device_destroy(mydev_class, dev_major);
	unregister_chrdev_region(dev_major, DEV_MAX);
    class_destroy(mydev_class);
    pr_info("\n");
}

module_init(sysfs_test_init)
module_exit(sysfs_test_exit)

MODULE_LICENSE("GPL");

